<template>
  <div class="chat-input">
    <!-- 附件预览 -->
    <div v-if="attachments.length > 0" class="attachments-preview">
      <div
        v-for="(attachment, index) in attachments"
        :key="attachment.id || index"
        class="attachment-preview-item"
        :class="`attachment-${attachment.type}`"
      >
        <!-- 图片预览 -->
        <div
          v-if="attachment.type === 'image'"
          class="attachment-image-preview"
        >
          <img
            :src="attachment.preview || attachment.url"
            :alt="attachment.name"
            class="preview-image"
          />
          <div class="attachment-overlay">
            <span class="attachment-name">{{ attachment.name }}</span>
            <Button
              type="danger"
              variant="text"
              icon="x"
              size="small"
              @click="removeAttachment(index)"
              class="remove-btn"
            />
          </div>
        </div>

        <!-- 文件预览 -->
        <div v-else class="attachment-file-preview">
          <Icon :name="getFileIcon(attachment)" :size="24" class="file-icon" />
          <div class="file-info">
            <span class="file-name">{{ attachment.name }}</span>
            <span class="file-size">{{ formatFileSize(attachment.size) }}</span>
          </div>
          <Button
            type="danger"
            variant="text"
            icon="x"
            size="small"
            @click="removeAttachment(index)"
            class="remove-btn"
          />
        </div>
      </div>
    </div>

    <!-- 输入区域 -->
    <div class="input-area">
      <!-- 工具栏 -->
      <div class="input-toolbar">
        <!-- 附件上传 -->
        <div class="toolbar-left">
          <input
            ref="fileInput"
            type="file"
            multiple
            accept="image/*,audio/*,video/*,.pdf,.doc,.docx,.txt,.zip,.rar"
            @change="handleFileSelect"
            style="display: none"
          />

          <Button
            type="secondary"
            variant="text"
            icon="paperclip"
            size="small"
            @click="triggerFileSelect"
            title="添加附件"
            :disabled="disabled"
          />

          <Button
            type="secondary"
            variant="text"
            icon="image"
            size="small"
            @click="triggerImageSelect"
            title="添加图片"
            :disabled="disabled"
          />

          <!-- 语音输入 -->
          <Button
            type="secondary"
            variant="text"
            :icon="isRecording ? 'mic-off' : 'mic'"
            size="small"
            @click="toggleRecording"
            :title="isRecording ? '停止录音' : '语音输入'"
            :disabled="disabled"
            :class="{ recording: isRecording }"
          />
        </div>

        <!-- 快捷操作 -->
        <div class="toolbar-right">
          <!-- 表情 -->
          <Button
            type="secondary"
            variant="text"
            icon="smile"
            size="small"
            @click="toggleEmojiPicker"
            title="表情"
            :disabled="disabled"
          />

          <!-- 设置 -->
          <Button
            type="secondary"
            variant="text"
            icon="settings"
            size="small"
            @click="toggleSettings"
            title="设置"
            :disabled="disabled"
          />
        </div>
      </div>

      <!-- 输入框 -->
      <div class="input-wrapper">
        <textarea
          ref="textareaRef"
          v-model="inputText"
          class="input-textarea"
          :placeholder="placeholder"
          :disabled="disabled"
          :maxlength="maxLength"
          @keydown="handleKeydown"
          @input="handleInput"
          @paste="handlePaste"
          @focus="handleFocus"
          @blur="handleBlur"
        ></textarea>

        <!-- 发送按钮 -->
        <div class="send-button-wrapper">
          <Button
            type="primary"
            icon="send"
            size="medium"
            @click="handleSend"
            :disabled="!canSend"
            :loading="sending"
            class="send-button"
            title="发送 (Ctrl+Enter)"
          />
        </div>
      </div>

      <!-- 输入提示 -->
      <div v-if="showHints" class="input-hints">
        <div class="hint-item">
          <span class="hint-key">Ctrl + Enter</span>
          <span class="hint-desc">发送消息</span>
        </div>
        <div class="hint-item">
          <span class="hint-key">Shift + Enter</span>
          <span class="hint-desc">换行</span>
        </div>
        <div v-if="maxLength" class="hint-item">
          <span class="hint-count">{{ inputText.length }}/{{ maxLength }}</span>
        </div>
      </div>
    </div>

    <!-- 表情选择器 -->
    <div v-if="showEmojiPicker" class="emoji-picker">
      <div class="emoji-categories">
        <Button
          v-for="category in emojiCategories"
          :key="category.name"
          type="secondary"
          variant="text"
          size="small"
          @click="selectEmojiCategory(category.name)"
          :class="{ active: selectedEmojiCategory === category.name }"
        >
          {{ category.icon }}
        </Button>
      </div>

      <div class="emoji-grid">
        <button
          v-for="emoji in currentEmojis"
          :key="emoji"
          class="emoji-item"
          @click="insertEmoji(emoji)"
        >
          {{ emoji }}
        </button>
      </div>
    </div>

    <!-- 录音状态 -->
    <div v-if="isRecording" class="recording-status">
      <div class="recording-indicator">
        <div class="recording-dot"></div>
        <span class="recording-text">正在录音...</span>
        <span class="recording-time">{{
          formatRecordingTime(recordingTime)
        }}</span>
      </div>

      <div class="recording-actions">
        <Button
          type="danger"
          variant="text"
          icon="x"
          size="small"
          @click="cancelRecording"
          title="取消录音"
        />

        <Button
          type="primary"
          variant="text"
          icon="check"
          size="small"
          @click="stopRecording"
          title="完成录音"
        />
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, nextTick, onMounted, onUnmounted } from "vue";
import Icon from "@/components/common/Icon.vue";
import Button from "@/components/common/Button.vue";

interface Attachment {
  id?: string;
  name: string;
  type: "image" | "file" | "audio";
  size: number;
  url?: string;
  preview?: string;
  file?: File;
}

interface Props {
  placeholder?: string;
  disabled?: boolean;
  maxLength?: number;
  showHints?: boolean;
  sending?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  placeholder: "输入消息...",
  disabled: false,
  maxLength: 2000,
  showHints: true,
  sending: false,
});

const emit = defineEmits<{
  send: [data: { text: string; attachments: Attachment[] }];
  input: [text: string];
  focus: [];
  blur: [];
  attachmentAdd: [attachment: Attachment];
  attachmentRemove: [index: number];
}>();

// 响应式数据
const inputText = ref("");
const attachments = ref<Attachment[]>([]);
const textareaRef = ref<HTMLTextAreaElement>();
const fileInput = ref<HTMLInputElement>();
const showEmojiPicker = ref(false);
const selectedEmojiCategory = ref("smileys");
const isRecording = ref(false);
const recordingTime = ref(0);
const mediaRecorder = ref<MediaRecorder | null>(null);
const recordingTimer = ref<number | null>(null);

// 计算属性
const canSend = computed(() => {
  return (
    !props.disabled &&
    !props.sending &&
    (inputText.value.trim() || attachments.value.length > 0)
  );
});

// 表情数据
const emojiCategories = [
  {
    name: "smileys",
    icon: "😀",
    emojis: [
      "😀",
      "😃",
      "😄",
      "😁",
      "😆",
      "😅",
      "😂",
      "🤣",
      "😊",
      "😇",
      "🙂",
      "🙃",
      "😉",
      "😌",
      "😍",
      "🥰",
      "😘",
      "😗",
      "😙",
      "😚",
      "😋",
      "😛",
      "😝",
      "😜",
      "🤪",
      "🤨",
      "🧐",
      "🤓",
      "😎",
      "🤩",
      "🥳",
    ],
  },
  {
    name: "gestures",
    icon: "👋",
    emojis: [
      "👋",
      "🤚",
      "🖐️",
      "✋",
      "🖖",
      "👌",
      "🤏",
      "✌️",
      "🤞",
      "🤟",
      "🤘",
      "🤙",
      "👈",
      "👉",
      "👆",
      "🖕",
      "👇",
      "☝️",
      "👍",
      "👎",
      "👊",
      "✊",
      "🤛",
      "🤜",
      "👏",
      "🙌",
      "👐",
      "🤲",
      "🤝",
      "🙏",
    ],
  },
  {
    name: "hearts",
    icon: "❤️",
    emojis: [
      "❤️",
      "🧡",
      "💛",
      "💚",
      "💙",
      "💜",
      "🖤",
      "🤍",
      "🤎",
      "💔",
      "❣️",
      "💕",
      "💞",
      "💓",
      "💗",
      "💖",
      "💘",
      "💝",
      "💟",
    ],
  },
];

const currentEmojis = computed(() => {
  const category = emojiCategories.find(
    (cat) => cat.name === selectedEmojiCategory.value,
  );
  return category?.emojis || [];
});

// 方法
const handleInput = () => {
  emit("input", inputText.value);
  adjustTextareaHeight();
};

const handleKeydown = (event: KeyboardEvent) => {
  if (event.key === "Enter") {
    if (event.ctrlKey || event.metaKey) {
      event.preventDefault();
      handleSend();
    } else if (!event.shiftKey) {
      // 可以配置是否允许Enter直接发送
      // event.preventDefault()
      // handleSend()
    }
  }
};

const handleSend = () => {
  if (!canSend.value) return;

  const text = inputText.value.trim();
  if (!text && attachments.value.length === 0) return;

  emit("send", {
    text,
    attachments: [...attachments.value],
  });

  // 清空输入
  inputText.value = "";
  attachments.value = [];
  adjustTextareaHeight();
};

const handleFocus = () => {
  emit("focus");
};

const handleBlur = () => {
  emit("blur");
};

const handlePaste = async (event: ClipboardEvent) => {
  const items = event.clipboardData?.items;
  if (!items) return;

  for (const item of items) {
    if (item.type.startsWith("image/")) {
      event.preventDefault();
      const file = item.getAsFile();
      if (file) {
        await addFileAttachment(file);
      }
    }
  }
};

const adjustTextareaHeight = () => {
  nextTick(() => {
    if (textareaRef.value) {
      textareaRef.value.style.height = "auto";
      const scrollHeight = textareaRef.value.scrollHeight;
      const maxHeight = 120; // 最大高度
      textareaRef.value.style.height = Math.min(scrollHeight, maxHeight) + "px";
    }
  });
};

// 文件处理
const triggerFileSelect = () => {
  if (fileInput.value) {
    fileInput.value.accept =
      "image/*,audio/*,video/*,.pdf,.doc,.docx,.txt,.zip,.rar";
    fileInput.value.click();
  }
};

const triggerImageSelect = () => {
  if (fileInput.value) {
    fileInput.value.accept = "image/*";
    fileInput.value.click();
  }
};

const handleFileSelect = (event: Event) => {
  const target = event.target as HTMLInputElement;
  const files = target.files;
  if (!files) return;

  Array.from(files).forEach((file) => {
    addFileAttachment(file);
  });

  // 清空input
  target.value = "";
};

const addFileAttachment = async (file: File) => {
  const attachment: Attachment = {
    id: Date.now().toString(),
    name: file.name,
    type: file.type.startsWith("image/") ? "image" : "file",
    size: file.size,
    file,
  };

  // 生成预览
  if (attachment.type === "image") {
    attachment.preview = await createImagePreview(file);
  }

  attachments.value.push(attachment);
  emit("attachmentAdd", attachment);
};

const createImagePreview = (file: File): Promise<string> => {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = (e) => {
      resolve(e.target?.result as string);
    };
    reader.readAsDataURL(file);
  });
};

const removeAttachment = (index: number) => {
  attachments.value.splice(index, 1);
  emit("attachmentRemove", index);
};

const formatFileSize = (bytes: number): string => {
  if (bytes === 0) return "0 B";

  const k = 1024;
  const sizes = ["B", "KB", "MB", "GB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));

  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
};

const getFileIcon = (attachment: Attachment): string => {
  const ext = attachment.name.split(".").pop()?.toLowerCase();

  const iconMap: Record<string, string> = {
    pdf: "file-text",
    doc: "file-text",
    docx: "file-text",
    txt: "file-text",
    xls: "file-spreadsheet",
    xlsx: "file-spreadsheet",
    ppt: "file-presentation",
    pptx: "file-presentation",
    zip: "file-archive",
    rar: "file-archive",
    "7z": "file-archive",
    mp3: "file-audio",
    wav: "file-audio",
    mp4: "file-video",
    avi: "file-video",
    mov: "file-video",
  };

  return iconMap[ext || ""] || "file";
};

// 表情处理
const toggleEmojiPicker = () => {
  showEmojiPicker.value = !showEmojiPicker.value;
};

const selectEmojiCategory = (category: string) => {
  selectedEmojiCategory.value = category;
};

const insertEmoji = (emoji: string) => {
  const textarea = textareaRef.value;
  if (!textarea) return;

  const start = textarea.selectionStart;
  const end = textarea.selectionEnd;
  const text = inputText.value;

  inputText.value = text.slice(0, start) + emoji + text.slice(end);

  nextTick(() => {
    const newPosition = start + emoji.length;
    textarea.setSelectionRange(newPosition, newPosition);
    textarea.focus();
    adjustTextareaHeight();
  });
};

// 语音录制
const toggleRecording = async () => {
  if (isRecording.value) {
    stopRecording();
  } else {
    await startRecording();
  }
};

const startRecording = async () => {
  try {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });

    mediaRecorder.value = new MediaRecorder(stream);
    const chunks: Blob[] = [];

    mediaRecorder.value.ondataavailable = (event) => {
      if (event.data.size > 0) {
        chunks.push(event.data);
      }
    };

    mediaRecorder.value.onstop = () => {
      const blob = new Blob(chunks, { type: "audio/webm" });
      const file = new File([blob], `录音_${Date.now()}.webm`, {
        type: "audio/webm",
      });
      addFileAttachment(file);

      // 停止所有音轨
      stream.getTracks().forEach((track) => track.stop());
    };

    mediaRecorder.value.start();
    isRecording.value = true;
    recordingTime.value = 0;

    // 开始计时
    recordingTimer.value = window.setInterval(() => {
      recordingTime.value++;
    }, 1000);
  } catch (error) {
    console.error("录音失败:", error);
    alert("无法访问麦克风，请检查权限设置");
  }
};

const stopRecording = () => {
  if (mediaRecorder.value && isRecording.value) {
    mediaRecorder.value.stop();
    isRecording.value = false;

    if (recordingTimer.value) {
      clearInterval(recordingTimer.value);
      recordingTimer.value = null;
    }
  }
};

const cancelRecording = () => {
  if (mediaRecorder.value && isRecording.value) {
    mediaRecorder.value.stop();
    isRecording.value = false;

    if (recordingTimer.value) {
      clearInterval(recordingTimer.value);
      recordingTimer.value = null;
    }

    // 不保存录音
    mediaRecorder.value = null;
  }
};

const formatRecordingTime = (seconds: number): string => {
  const mins = Math.floor(seconds / 60);
  const secs = seconds % 60;
  return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
};

// 设置
const toggleSettings = () => {
  // 触发设置弹窗
  console.log("打开设置");
};

// 生命周期
onMounted(() => {
  adjustTextareaHeight();

  // 点击外部关闭表情选择器
  document.addEventListener("click", handleClickOutside);
});

onUnmounted(() => {
  document.removeEventListener("click", handleClickOutside);

  // 清理录音
  if (recordingTimer.value) {
    clearInterval(recordingTimer.value);
  }
});

const handleClickOutside = (event: Event) => {
  const target = event.target as Element;
  if (!target.closest(".emoji-picker") && !target.closest('[title="表情"]')) {
    showEmojiPicker.value = false;
  }
};

// 公开方法
const focus = () => {
  textareaRef.value?.focus();
};

const clear = () => {
  inputText.value = "";
  attachments.value = [];
  adjustTextareaHeight();
};

defineExpose({
  focus,
  clear,
});
</script>

<style scoped>
/* 聊天输入基础样式 */
.chat-input {
  background-color: var(--bg-primary);
  border-top: 1px solid var(--border-color);
  position: relative;
}

/* 附件预览 */
.attachments-preview {
  padding: 12px 16px 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-height: 200px;
  overflow-y: auto;
}

.attachment-preview-item {
  position: relative;
  border-radius: 8px;
  overflow: hidden;
  background-color: var(--bg-secondary);
}

/* 图片预览 */
.attachment-image-preview {
  position: relative;
  width: 80px;
  height: 80px;
}

.preview-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.attachment-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.7) 0%,
    transparent 50%,
    rgba(0, 0, 0, 0.7) 100%
  );
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 4px;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.attachment-image-preview:hover .attachment-overlay {
  opacity: 1;
}

.attachment-name {
  font-size: 10px;
  color: white;
  text-overflow: ellipsis;
  overflow: hidden;
  white-space: nowrap;
}

.remove-btn {
  align-self: flex-end;
}

/* 文件预览 */
.attachment-file-preview {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  min-width: 200px;
  border: 1px solid var(--border-color);
}

.file-icon {
  color: var(--text-secondary);
  flex-shrink: 0;
}

.file-info {
  flex: 1;
  min-width: 0;
}

.file-name {
  display: block;
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.file-size {
  display: block;
  font-size: 10px;
  color: var(--text-tertiary);
  margin-top: 2px;
}

/* 输入区域 */
.input-area {
  padding: 12px 16px;
}

/* 工具栏 */
.input-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.toolbar-left,
.toolbar-right {
  display: flex;
  gap: 4px;
}

.recording {
  color: var(--error-color) !important;
  animation: pulse 1s ease-in-out infinite;
}

/* 输入框 */
.input-wrapper {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  background-color: var(--bg-secondary);
  border: 1px solid var(--border-color);
  border-radius: 12px;
  padding: 8px 12px;
  transition: border-color 0.2s ease;
}

.input-wrapper:focus-within {
  border-color: var(--primary-color);
}

.input-textarea {
  flex: 1;
  min-height: 20px;
  max-height: 120px;
  border: none;
  outline: none;
  background: transparent;
  color: var(--text-primary);
  font-size: 14px;
  line-height: 1.4;
  resize: none;
  font-family: inherit;
}

.input-textarea::placeholder {
  color: var(--text-tertiary);
}

.send-button-wrapper {
  flex-shrink: 0;
}

.send-button {
  border-radius: 8px;
}

/* 输入提示 */
.input-hints {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 8px;
  font-size: 11px;
  color: var(--text-tertiary);
}

.hint-item {
  display: flex;
  align-items: center;
  gap: 4px;
}

.hint-key {
  background-color: var(--bg-tertiary);
  padding: 2px 6px;
  border-radius: 4px;
  font-family: monospace;
}

.hint-count {
  font-weight: 500;
}

/* 表情选择器 */
.emoji-picker {
  position: absolute;
  bottom: 100%;
  left: 16px;
  right: 16px;
  background-color: var(--bg-primary);
  border: 1px solid var(--border-color);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  z-index: 1000;
  max-height: 300px;
  overflow: hidden;
}

.emoji-categories {
  display: flex;
  border-bottom: 1px solid var(--border-color);
  padding: 8px;
  gap: 4px;
}

.emoji-categories .active {
  background-color: var(--primary-color);
  color: white;
}

.emoji-grid {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 4px;
  padding: 8px;
  max-height: 200px;
  overflow-y: auto;
}

.emoji-item {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  background: transparent;
  border-radius: 6px;
  font-size: 18px;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.emoji-item:hover {
  background-color: var(--bg-secondary);
}

/* 录音状态 */
.recording-status {
  position: absolute;
  bottom: 100%;
  left: 16px;
  right: 16px;
  background-color: var(--bg-primary);
  border: 1px solid var(--border-color);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  padding: 12px 16px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  z-index: 1000;
}

.recording-indicator {
  display: flex;
  align-items: center;
  gap: 8px;
}

.recording-dot {
  width: 8px;
  height: 8px;
  background-color: var(--error-color);
  border-radius: 50%;
  animation: pulse 1s ease-in-out infinite;
}

.recording-text {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-primary);
}

.recording-time {
  font-size: 12px;
  color: var(--text-secondary);
  font-family: monospace;
}

.recording-actions {
  display: flex;
  gap: 8px;
}

/* 动画 */
@keyframes pulse {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.7;
    transform: scale(1.1);
  }
}

/* 响应式 */
@media (max-width: 768px) {
  .input-area {
    padding: 8px 12px;
  }

  .input-toolbar {
    margin-bottom: 6px;
  }

  .toolbar-left,
  .toolbar-right {
    gap: 2px;
  }

  .input-wrapper {
    padding: 6px 10px;
  }

  .input-textarea {
    font-size: 16px; /* 防止iOS缩放 */
  }

  .emoji-picker {
    left: 8px;
    right: 8px;
  }

  .emoji-grid {
    grid-template-columns: repeat(6, 1fr);
  }

  .attachment-file-preview {
    min-width: 150px;
  }
}

@media (max-width: 480px) {
  .input-area {
    padding: 6px 8px;
  }

  .input-hints {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }

  .emoji-grid {
    grid-template-columns: repeat(5, 1fr);
  }

  .attachments-preview {
    padding: 8px 8px 0;
  }

  .attachment-file-preview {
    min-width: 120px;
    padding: 6px 8px;
  }
}

/* 暗色主题适配 */
@media (prefers-color-scheme: dark) {
  .input-wrapper:focus-within {
    box-shadow: 0 0 0 1px var(--primary-color);
  }
}

/* 无障碍支持 */
@media (prefers-reduced-motion: reduce) {
  .recording,
  .recording-dot {
    animation: none;
  }

  .attachment-overlay {
    transition: none;
  }
}

/* 滚动条样式 */
.attachments-preview::-webkit-scrollbar,
.emoji-grid::-webkit-scrollbar {
  width: 6px;
}

.attachments-preview::-webkit-scrollbar-track,
.emoji-grid::-webkit-scrollbar-track {
  background: var(--bg-tertiary);
  border-radius: 3px;
}

.attachments-preview::-webkit-scrollbar-thumb,
.emoji-grid::-webkit-scrollbar-thumb {
  background: var(--text-tertiary);
  border-radius: 3px;
}

.attachments-preview::-webkit-scrollbar-thumb:hover,
.emoji-grid::-webkit-scrollbar-thumb:hover {
  background: var(--text-secondary);
}
</style>
